在一些中后台应用的开发中,有些业务往往需要用到流程设计器,比如:管理网络、审批流程等等...正是因为有多种业务都需要使用到流程图的功能,所以对于能快速产出一个流程设计器是非常必须的
工具选择
古话说的好,预先善其事,必先利其器。所以首先要做的就是选择一个合适的开源基础库,站在巨人的肩膀上,总是跑的更快
开源时代,社区的资源总是非常丰富,身为小程序媛的我漏出幸福的微笑😊
- joint.js 支持多种交互式图表创建,但有收费版本和免费版本的区分,更丰富的功能可能就需要收费了
- jsPlumb 是一套完全开源的流程图创建工具,上手简单,底层是基于 Canvas 技术,但唯一美中不足的是,基于 jQuery,所以对于大批量流程的操作,在性能上可能不能达到最佳
- d3 d3 应该很多人都熟悉,非常好的可视化基础库,相应的,上手成本相对高一些
- spritejs 同样是基于 Canvas,据说是月影大大一个人写的(✨✨眼),官网写的超好啦...
- ggEditor 蚂蚁金服数据可视化团队的大神高力结合 react + g6 开源的流程库,它的前身是 g6Editor,也是他们团队开源的产品,官方说法是学习成本太高,停止了对外支持。底层也是 Canvas 技术,虽然 ggEditor 目前开源的文档不多,但是潜力无穷,使用起来非常便捷,上手也比较简单,貌似是去年开源的,社区相对还没那么活跃,所以它的使用依然是一个摸索的过程
最终,我选择了 ggEditor
,因为它完全开源,使用很简单,很轻量级,而且天然基于 react,非常完美
快速构建
引用 ggEditor
我们可以按照 github 上 ggEditor 的安装步骤操作
启动之后的界面效果可以参考:http://ggeditor.com/demo/#/flow
我们可以看到它的官方 demo 功能是比较齐全的,基本上已经实现了一个元素拖拽及元素属性编辑的完整功能
属性解析
我们知道整个流程编辑器基本可以分为三部分,一部分是左侧的元素面板区,另一部分是右侧的元素属性配置区,再就是中间的流程展示区,每个流程元素上可以有相应的事件响应
所以这里主要介绍以上相应的属性
-
- 其中 type 有 node 和 edge 两个值可选,node 就是节点,edge 是连接节点的连线,当我们初始化加载元素和保存导出元素数据时也是以这两种为key
- shape 可选参数有:圆形
flow-circle
| 圆角矩形flow-rect
| 菱形flow-rhombus
| 椭圆矩形flow-capsule
- src 可以引入一张图片作为当前节点的预览样式
- 编辑器画板中的样式是由 model 决定,model 默认会继承
- 组件的
props.shape
和props.size
,所以通常 model 只需配置 color、label。配置项如下:model: { color: '#333', // 节点主题色(选中颜色、激活颜色基于该值) size: [10, 10], // [x, y] 节点尺寸 shape: 'cirle', // 图形:圆形 circle | 圆角矩形 rect | 菱形 rhombus | 椭圆矩形 capsule style: { // 关键形样式(可覆盖color的普通样式,但激活、选中依然无效,坑!) fill: 'red', // 填充背景 stroke: 'blue' // 形状描边 }, label: { // 节点标签 text: '开始节点', // 文本内容 fill: 'green' // 文本颜色 }, index: 1 // 渲染层级 }
- 组件的
-
Flow 编辑器配置
在组件上,最重要的是监听事件:
js <Flow onNodeClick={(e) => { console.log(e); }}/>
更多的我们可以参考页面事件 Page Events-
拖拽节点时,区分是新节点还是旧节点。可以用
onDrop
- 监听拖拽放置事件,如果是从元素面板区拖拽新节点到画布上,onDrop
返回的事件对象中currentItem
和currentShape
都是undefined
。而如果是挪动旧节点的位置,这两个字段会记录拖动的图形图项。当然,也可以监听节点拖动结束事件 -onNodeDragEnd
,这个事件只会在拖动画布上的节点时才触发 -
锚点连线取消,比如有一个需求是当目标节点已经连线的时候,就取消连线。可以用
onAfterChange
事件,根据 item(type: 'edge') 或者 model(source:'xxxx') 对象中的参数进行判断。最后用结合异步函数和<withPropsAPI>
组件取消连线:handleAddItem = (e) => { this.apiAction('undo') } apiAction = (command) => { const { propsAPI } = this.props setTimeout(() => { propsAPI.executeCommand(command) }, 0) }
<withPropsAPI>
是 ggEditor 自带的包装组件,同时它又自带propsAPI
属性,更多的属性值我们可以参考 propsAPI -
保存数据。上面
<withPropsAPI>
提供的propsAPI
属性中,包含了save()
方法。我们可以封装一个SaveButton
组件,暴露一个onSave
事件,然后用<withPropsAPI>
包装该组件。具体可参考 demo -
自定义键盘操作。可以通过监听
onKeyDown
和onKeyUp
手动创建多个快捷命令handleKeyUp = e => { // 键盘抬起时重置记录的按键 this.keysDown = '' } handleKeyDown = e => { // 拼接按键命令 if (this.keysDown.length === 0) { this.keysDown = e.domEvent.key } else { this.keysDown += `+${e.domEvent.key}` } // 自定义键盘操作 switch (this.keysDown) { case 'Meta+c': this.diyCopyCommand() break case 'Control+c': this.diyCopyCommand() break case 'Meta+v': this.diyPasteCommand() break case 'Control+v': this.diyPasteCommand() break default: break } } // 自定义复制 diyCopyCommand = () => { const { propsAPI } = this.props let selected = propsAPI.getSelected() if (selected.length > 0) { this.commandAction('copy') } } // 自定义粘贴 diyPasteCommand = () => { this.commandAction('paste') }
-
以上只是 ggEditor 的核心组件和功能。还有很多组件没有提交,比如 <Minimap>
、<ContextMenu>
、<Toolbar>
,我们可以具体去看项目 demo
其他的属性解析可以参考官网 API
自定义节点
如果 <Item>
自带的参数不满足需求,可以使用 <ReisterNode>
来封装自己的 <Item>
比如自定义一个 start-node
,就可以自行封装一个 node 组件
具体可以参考 Issues
兼容 IE11
ggEditor 是基于 umijs 脚手架的, umijs不得不说,太简单粗暴,默认不支持IE,如果需要支持,需要我们开启配置
需要在 .umirc.js 中配置
targets: {
ie: 11,
}
dva 版本问题
Chrome warning
IE bug
查看后发现都是指向同一个问题,因为 dva 的最新版本,具体可以看看升级dva最新版提示Warning: Please use require("dva").dynamic
instead of require("dva/dynamic")
. Support for the latter will be removed in the next major release. 和 2.6.0-beta.4 版本新抛出警告
为了快速解决这个问题,我去瞅了眼 ant-design-pro,发现它三天前提交的,但是dva版本仍是用的低版本,非常 nice
以上,便可快速解决 IE11 白屏的问题
参考文档
在 React 项目中引入 GG-Editor 编辑可视化流程
PS:终于用上自己写的博客系统写文章啦,体验还是非常八错的 😊😊